﻿// AES128_CMAC_Algorithm.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

/**
 * @file validation.c
 * @author Jason Conway (jpc@jasonconway.dev)
 * @version 2024.05
 * @date 2024-05-04
 * @ref https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
 *
 * @copyright This example is free and unencumbered software released into the public domain.
 *
 */
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "AES128/aes128.h"

static void xmemprint(const char* str, const uint8_t* src, size_t len)
{
    printf("%-21s", str);
    for (size_t i = 0; i < len; i += 4) {
        char hex[] = "---------";
        for (size_t j = 0; j < 4; j++) {
            hex[2 * j + 0] = "0123456789abcdef"[src[j + i] >> 4];
            hex[2 * j + 1] = "0123456789abcdef"[src[j + i] & 15];
        }
        if (i + 4 >= len) {
            hex[8] = '\n';
        }
        printf("%s", hex);
    }
}

static bool test_encrypt(void)
{
    printf("CBC-AES128.Encrypt\n");
    uint8_t key[] = {
        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    };

    uint8_t iv[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    };

    uint8_t chunk[] = {
        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
    };

    uint8_t expected[] = {
        0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
        0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
        0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
        0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
        0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
        0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
        0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
        0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
    };

    xmemprint("key: ", key, sizeof(key));
    xmemprint("iv: ", iv, sizeof(iv));
    xmemprint("plaintext block 1: ", &chunk[0x00], 0x10);
    xmemprint("plaintext block 2: ", &chunk[0x10], 0x10);
    xmemprint("plaintext block 3: ", &chunk[0x20], 0x10);
    xmemprint("plaintext block 4: ", &chunk[0x30], 0x10);

    aes128_t ctx;
    aes128_init(&ctx, iv, key);
    aes128_encrypt(&ctx, chunk, 64);

    xmemprint("ciphertext block 1: ", &chunk[0x00], 0x10);
    xmemprint("expected output: ", &expected[0x00], 0x10);
    xmemprint("ciphertext block 2: ", &chunk[0x10], 0x10);
    xmemprint("expected output: ", &expected[0x10], 0x10);
    xmemprint("ciphertext block 3: ", &chunk[0x20], 0x10);
    xmemprint("expected output: ", &expected[0x20], 0x10);
    xmemprint("ciphertext block 4: ", &chunk[0x30], 0x10);
    xmemprint("expected output: ", &expected[0x30], 0x10);
    printf("\n");
    return !memcmp(chunk, expected, 64);
}

static bool test_decrypt(void)
{
    printf("CBC-AES128.Decrypt\n");
    uint8_t key[] = {
        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    };

    uint8_t iv[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    };

    uint8_t chunk[] = {
        0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
        0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
        0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
        0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
        0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
        0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
        0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
        0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
    };

    uint8_t expected[] = {
        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
    };

    xmemprint("key: ", key, sizeof(key));
    xmemprint("iv: ", iv, sizeof(iv));

    xmemprint("ciphertext block 1: ", &chunk[0x00], 0x10);
    xmemprint("ciphertext block 2: ", &chunk[0x10], 0x10);
    xmemprint("ciphertext block 3: ", &chunk[0x20], 0x10);
    xmemprint("ciphertext block 4: ", &chunk[0x30], 0x10);

    aes128_t ctx;
    aes128_init(&ctx, iv, key);
    aes128_decrypt(&ctx, chunk, 64);

    xmemprint("plaintext block 1:  ", &chunk[0x00], 0x10);
    xmemprint("expected output: ", &expected[0x00], 0x10);
    xmemprint("plaintext block 2:  ", &chunk[0x10], 0x10);
    xmemprint("expected output: ", &expected[0x10], 0x10);
    xmemprint("plaintext block 3:  ", &chunk[0x20], 0x10);
    xmemprint("expected output: ", &expected[0x20], 0x10);
    xmemprint("plaintext block 4:  ", &chunk[0x30], 0x10);
    xmemprint("expected output: ", &expected[0x30], 0x10);

    return !memcmp(chunk, expected, 64);
}

int main(void)
{
    assert(test_encrypt() && test_decrypt());

    return 0;
}

